package com.moon.cloud.common.utils;

import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 验证工具类
 */
public class ValidateUtils {

    /** 手机号验证正则表达式模式 */
    private static final Pattern MOBILE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    /** 邮箱验证正则表达式模式 */
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$");
    /** 身份证号验证正则表达式模式 */
    private static final Pattern ID_CARD_PATTERN = Pattern.compile("^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");
    /** URL验证正则表达式模式 */
    private static final Pattern URL_PATTERN = Pattern.compile("^(https?|ftp)://[^\\s/$.?#].[^\\s]*$");
    /** IP地址验证正则表达式模式 */
    private static final Pattern IP_PATTERN = Pattern.compile("^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$");
    /** 中文验证正则表达式模式 */
    private static final Pattern CHINESE_PATTERN = Pattern.compile("^[\\u4e00-\\u9fa5]+$");
    /** 字母验证正则表达式模式 */
    private static final Pattern LETTER_PATTERN = Pattern.compile("^[a-zA-Z]+$");
    /** 数字验证正则表达式模式 */
    private static final Pattern NUMBER_PATTERN = Pattern.compile("^\\d+$");
    /** 字母和数字验证正则表达式模式 */
    private static final Pattern LETTER_NUMBER_PATTERN = Pattern.compile("^[a-zA-Z0-9]+$");

    /**
     * 验证手机号
     *
     * @param mobile 手机号码字符串
     * @return 如果手机号格式正确返回true，否则返回false
     */
    public static boolean isMobile(String mobile) {
        return StringUtils.isNotEmpty(mobile) && MOBILE_PATTERN.matcher(mobile).matches();
    }

    /**
     * 验证邮箱
     *
     * @param email 邮箱地址字符串
     * @return 如果邮箱格式正确返回true，否则返回false
     */
    public static boolean isEmail(String email) {
        return StringUtils.isNotEmpty(email) && EMAIL_PATTERN.matcher(email).matches();
    }

    /**
     * 验证身份证号
     *
     * @param idCard 身份证号码字符串
     * @return 如果身份证号格式正确返回true，否则返回false
     */
    public static boolean isIdCard(String idCard) {
        return StringUtils.isNotEmpty(idCard) && ID_CARD_PATTERN.matcher(idCard).matches();
    }

    /**
     * 验证 URL
     *
     * @param url URL字符串
     * @return 如果URL格式正确返回true，否则返回false
     */
    public static boolean isUrl(String url) {
        return StringUtils.isNotEmpty(url) && URL_PATTERN.matcher(url).matches();
    }

    /**
     * 验证 IP 地址
     *
     * @param ip IP地址字符串
     * @return 如果IP地址格式正确返回true，否则返回false
     */
    public static boolean isIp(String ip) {
        return StringUtils.isNotEmpty(ip) && IP_PATTERN.matcher(ip).matches();
    }

    /**
     * 验证是否为纯中文
     *
     * @param str 待验证字符串
     * @return 如果字符串只包含中文字符返回true，否则返回false
     */
    public static boolean isChinese(String str) {
        return StringUtils.isNotEmpty(str) && CHINESE_PATTERN.matcher(str).matches();
    }

    /**
     * 验证是否为纯字母
     *
     * @param str 待验证字符串
     * @return 如果字符串只包含字母返回true，否则返回false
     */
    public static boolean isLetter(String str) {
        return StringUtils.isNotEmpty(str) && LETTER_PATTERN.matcher(str).matches();
    }

    /**
     * 验证是否为纯数字
     *
     * @param str 待验证字符串
     * @return 如果字符串只包含数字返回true，否则返回false
     */
    public static boolean isNumber(String str) {
        return StringUtils.isNotEmpty(str) && NUMBER_PATTERN.matcher(str).matches();
    }

    /**
     * 验证是否为字母+数字
     *
     * @param str 待验证字符串
     * @return 如果字符串只包含字母和数字返回true，否则返回false
     */
    public static boolean isLetterNumber(String str) {
        return StringUtils.isNotEmpty(str) && LETTER_NUMBER_PATTERN.matcher(str).matches();
    }

    /**
     * 验证字符串长度范围
     *
     * @param str 待验证字符串
     * @param min 最小长度
     * @param max 最大长度
     * @return 如果字符串长度在指定范围内返回true，否则返回false
     */
    public static boolean lengthBetween(String str, int min, int max) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        int length = str.length();
        return length >= min && length <= max;
    }

    /**
     * 验证数字范围
     *
     * @param value 待验证的整数值
     * @param min 最小值
     * @param max 最大值
     * @return 如果数值在指定范围内返回true，否则返回false
     */
    public static boolean between(Integer value, int min, int max) {
        if (value == null) {
            return false;
        }
        return value >= min && value <= max;
    }

    /**
     * 验证数字范围（Long）
     *
     * @param value 待验证的长整数值
     * @param min 最小值
     * @param max 最大值
     * @return 如果数值在指定范围内返回true，否则返回false
     */
    public static boolean between(Long value, long min, long max) {
        if (value == null) {
            return false;
        }
        return value >= min && value <= max;
    }

    /**
     * 验证集合大小范围
     *
     * @param collection 待验证的集合
     * @param min 最小大小
     * @param max 最大大小
     * @return 如果集合大小在指定范围内返回true，否则返回false
     */
    public static boolean sizeBetween(Collection<?> collection, int min, int max) {
        if (collection == null) {
            return false;
        }
        int size = collection.size();
        return size >= min && size <= max;
    }

    /**
     * 验证不为 null
     *
     * @param obj 待验证对象
     * @return 如果对象不为null返回true，否则返回false
     */
    public static boolean notNull(Object obj) {
        return obj != null;
    }

    /**
     * 验证不为空字符串
     *
     * @param str 待验证字符串
     * @return 如果字符串不为空返回true，否则返回false
     */
    public static boolean notEmpty(String str) {
        return StringUtils.isNotEmpty(str);
    }

    /**
     * 验证不为空白字符串
     *
     * @param str 待验证字符串
     * @return 如果字符串不为空白返回true，否则返回false
     */
    public static boolean notBlank(String str) {
        return StringUtils.isNotBlank(str);
    }

    /**
     * 验证集合不为空
     *
     * @param collection 待验证集合
     * @return 如果集合不为空返回true，否则返回false
     */
    public static boolean notEmpty(Collection<?> collection) {
        return CollectionUtils.isNotEmpty(collection);
    }

    /**
     * 验证 Map 不为空
     *
     * @param map 待验证的Map
     * @return 如果Map不为空返回true，否则返回false
     */
    public static boolean notEmpty(Map<?, ?> map) {
        return CollectionUtils.isNotEmpty(map);
    }

    /**
     * 验证数组不为空
     *
     * @param array 待验证数组
     * @return 如果数组不为空返回true，否则返回false
     */
    public static boolean notEmpty(Object[] array) {
        return CollectionUtils.isNotEmpty(array);
    }

    /**
     * 验证是否为正整数
     *
     * @param value 待验证的整数值
     * @return 如果数值大于0返回true，否则返回false
     */
    public static boolean isPositive(Integer value) {
        return value != null && value > 0;
    }

    /**
     * 验证是否为正整数（Long）
     *
     * @param value 待验证的长整数值
     * @return 如果数值大于0返回true，否则返回false
     */
    public static boolean isPositive(Long value) {
        return value != null && value > 0;
    }

    /**
     * 验证是否为非负整数
     *
     * @param value 待验证的整数值
     * @return 如果数值大于等于0返回true，否则返回false
     */
    public static boolean isNonNegative(Integer value) {
        return value != null && value >= 0;
    }

    /**
     * 验证是否为非负整数（Long）
     *
     * @param value 待验证的长整数值
     * @return 如果数值大于等于0返回true，否则返回false
     */
    public static boolean isNonNegative(Long value) {
        return value != null && value >= 0;
    }

    /**
     * 验证密码强度（至少包含字母和数字，长度 6-20）
     *
     * @param password 待验证密码
     * @return 如果密码符合强度要求返回true，否则返回false
     */
    public static boolean isStrongPassword(String password) {
        if (StringUtils.isEmpty(password)) {
            return false;
        }
        if (!lengthBetween(password, 6, 20)) {
            return false;
        }
        boolean hasLetter = password.matches(".*[a-zA-Z].*");
        boolean hasNumber = password.matches(".*\\d.*");
        return hasLetter && hasNumber;
    }

    /**
     * 验证是否包含中文
     *
     * @param str 待验证字符串
     * @return 如果字符串包含中文字符返回true，否则返回false
     */
    public static boolean containsChinese(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return str.matches(".*[\\u4e00-\\u9fa5].*");
    }

    /**
     * 验证是否包含特殊字符
     *
     * @param str 待验证字符串
     * @return 如果字符串包含特殊字符返回true，否则返回false
     */
    public static boolean containsSpecialChar(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        }
        return str.matches(".*[^a-zA-Z0-9\\u4e00-\\u9fa5].*");
    }

    /**
     * 验证用户名（字母开头，字母数字下划线，4-16位）
     *
     * @param username 待验证用户名
     * @return 如果用户名符合规则返回true，否则返回false
     */
    public static boolean isUsername(String username) {
        if (StringUtils.isEmpty(username)) {
            return false;
        }
        return username.matches("^[a-zA-Z][a-zA-Z0-9_]{3,15}$");
    }

    /**
     * 验证是否在指定的枚举值中
     *
     * @param <T> 泛型类型
     * @param value 待验证的值
     * @param values 枚举值数组
     * @return 如果值在枚举数组中返回true，否则返回false
     */
    @SafeVarargs
    public static <T> boolean in(T value, T... values) {
        if (value == null || values == null) {
            return false;
        }
        for (T v : values) {
            if (value.equals(v)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 验证是否不在指定的枚举值中
     *
     * @param <T> 泛型类型
     * @param value 待验证的值
     * @param values 枚举值数组
     * @return 如果值不在枚举数组中返回true，否则返回false
     */
    @SafeVarargs
    public static <T> boolean notIn(T value, T... values) {
        return !in(value, values);
    }

    /**
     * 断言为真，否则抛异常
     *
     * @param condition 断言条件
     * @param message 异常消息
     * @throws IllegalArgumentException 如果条件为false则抛出此异常
     */
    public static void assertTrue(boolean condition, String message) {
        if (!condition) {
            throw new IllegalArgumentException(message);
        }
    }

    /**
     * 断言不为 null，否则抛异常
     *
     * @param obj 待断言对象
     * @param message 异常消息
     * @throws IllegalArgumentException 如果对象为null则抛出此异常
     */
    public static void assertNotNull(Object obj, String message) {
        if (obj == null) {
            throw new IllegalArgumentException(message);
        }
    }

    /**
     * 断言不为空字符串，否则抛异常
     *
     * @param str 待断言字符串
     * @param message 异常消息
     * @throws IllegalArgumentException 如果字符串为空则抛出此异常
     */
    public static void assertNotEmpty(String str, String message) {
        if (StringUtils.isEmpty(str)) {
            throw new IllegalArgumentException(message);
        }
    }

    /**
     * 断言不为空白字符串，否则抛异常
     *
     * @param str 待断言字符串
     * @param message 异常消息
     * @throws IllegalArgumentException 如果字符串为空白则抛出此异常
     */
    public static void assertNotBlank(String str, String message) {
        if (StringUtils.isBlank(str)) {
            throw new IllegalArgumentException(message);
        }
    }

    /**
     * 断言集合不为空，否则抛异常
     *
     * @param collection 待断言集合
     * @param message 异常消息
     * @throws IllegalArgumentException 如果集合为空则抛出此异常
     */
    public static void assertNotEmpty(Collection<?> collection, String message) {
        if (CollectionUtils.isEmpty(collection)) {
            throw new IllegalArgumentException(message);
        }
    }
}
